/**
 * @description Combines members of an intersection into a readable type.
 *
 * @link https://twitter.com/mattpocockuk/status/1622730173446557697?s=20&t=NdpAcmEFXY01xkqU3KO0Mg
 * @example
 * Prettify<{ a: string } | { b: string } | { c: number, d: bigint }>
 * => { a: string, b: string, c: number, d: bigint }
 */
export type Prettify<T> = {
  [K in keyof T]: T[K];
} & {};

/**
 * @description Creates a type with all keys K from T as non-null.
 */
export type NonNull<T> = {
  [P in keyof T]-?: NonNullable<T[P]>;
};

export type PonderTypeError<error extends string> = error;

export type DeepPartial<T> = {
  [P in keyof T]?: T[P] extends (infer U)[]
    ? DeepPartial<U>[]
    : T[P] extends object
      ? DeepPartial<T[P]>
      : T[P];
};

/**
 * @description Creates a partial type with the selected keys required.
 *
 * @example
 * type t = PartialExcept<{ a: string, b: boolean }, "a">
 * //   ^? t: { a: string, b?: boolean }
 */
export type PartialExcept<T, K extends keyof T> = {
  [P in K]: T[P];
} & {
  [P in keyof Omit<T, K>]?: T[P];
};

/**
 * @description Marks a property of an object as optional.
 */
export type MakeOptional<T, K extends keyof T> = Omit<T, K> &
  Partial<Pick<T, K>>;
